package com.ncr.travel.appmgr.service.rest;

import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.ncr.travel.appmgr.model.ApplicationConfigurationJson;
import com.ncr.travel.appmgr.model.shared.ApplicationConfiguration;
import com.ncr.travel.appmgr.model.shared.Rule;
import com.ncr.travel.appmgr.model.shared.Theme;
import com.ncr.travel.appmgr.service.ApplicationManagerService;
import com.ncr.travel.appmgr.service.mapper.AppManagerObjectMapper;
import com.ncr.travel.appmgr.service.model.ProductsResponse;
import com.ncr.travel.appmgr.service.model.ScreenConfiguration;

/**
 * @author as185325
 * 
 */
@Controller
public class ApplicationManagerController {

	private static final Logger logger = LoggerFactory.getLogger(ApplicationManagerController.class);

	private final ApplicationManagerService applicationManagerService;
	private final AppManagerObjectMapper mapper;

	@Autowired
	public ApplicationManagerController(ApplicationManagerService applicationManagerService, AppManagerObjectMapper mapper) {
		super();
		this.applicationManagerService = applicationManagerService;
		this.mapper = mapper;
	}

	@RequestMapping(value = "/", method = RequestMethod.GET)
	@ResponseBody
	public String home() {
		return "Welcome to Shared Travel Framework Application Services" + " V.4";
	}

	/**
	 * Returns a Theme with given theme id.
	 * 
	 * @param themeUUID
	 * @return Theme as Json document.
	 */
	@RequestMapping(value = "themeByUUID", method = RequestMethod.GET)
	@ResponseBody
	public String getThemeByUUID(@RequestParam String themeUUID) {
		String response = null;
		try {
			Theme theme = applicationManagerService.getThemeByUUID(themeUUID);
			if (theme == null) {
				response = createErrorJsonDocument(1000, "No theme exists with given UUID.");
			} else {
				response = convertToJsonDocument(theme);
			}
		} catch (IllegalArgumentException iae) {
			logger.error("Invalid theme UUID: " + themeUUID);
			response = createErrorJsonDocument(5678, "Invalid theme UUID.");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = createErrorJsonDocument(1234, "Technical Error.");
		}
		logger.info("Returning theme, theme UUID: " + themeUUID + ", theme: " + response);
		return response;
	}

	/**
	 * Returns a Theme with given theme name.
	 * 
	 * @param themeName
	 * @param version
	 * @return Theme as json document.
	 */
	@RequestMapping(value = "themeByNameVersion", method = RequestMethod.GET)
	@ResponseBody
	public String getThemeByNameVersion(@RequestParam String themeName, @RequestParam String version) {
		String response = null;
		try {
			Theme theme = applicationManagerService.getThemeByNameVersion(themeName, version);
			if (theme == null) {
				response = createErrorJsonDocument(1001, "No theme exists with given name and version.");
			} else {
				response = convertToJsonDocument(theme);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = createErrorJsonDocument(1234, "Technical Error.");
		}
		logger.info("Returning theme, themeName: " + themeName + ", version: " + version + ", theme: " + response);
		return response;
	}

	/**
	 * Returns the screen configuration data for a screen.
	 * 
	 * @param key
	 *            product key
	 * @param path
	 *            full path to the configuration after product key
	 * @return Screen configuration data as json document.
	 */
	@RequestMapping(value = "config/{key}/{path}", method = RequestMethod.GET)
	@ResponseBody
	public String findConfigurationByKeyAndPath(@PathVariable("key") String key, @PathVariable("path") String path) {
		String response = null;
		try {
			ScreenConfiguration config = applicationManagerService.findConfigurationByKeyAndPath(key, path);
			if (config == null) {
				response = createErrorJsonDocument(2001, "No screen found for screen: '" + path + "' and key: '" + key + "'");
			} else {
				response = convertToJsonDocument(config);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response = createErrorJsonDocument(1234, "Technical Error.");
		}
		logger.info("Returning screenConfiguration, for screen: '" + path + "' and key: '" + key + "', screenConfiguration: " + response);
		return response;
	}

	/**
	 * Returns the list of product names for a given user name.
	 * 
	 * @param userName
	 * @return list of product names as json document
	 * @throws Exception
	 */
	@RequestMapping(value = "products", method = RequestMethod.GET)
	@ResponseBody
	public String getProducts(@RequestParam String userName) throws Exception {
		String jsonString = null;
		try {
			ProductsResponse response = applicationManagerService.getProducts(userName);
			ApplicationConfiguration config = new ApplicationConfigurationJson();
			config.setProducts(response.getProducts());
			config.setUserName(userName);
			if (response != null) {
				response.setUserName(userName);
			}
			jsonString = convertToJsonDocument(config);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			jsonString = createErrorJsonDocument(1234, "Technical Error.");
		}
		logger.info("Returning list of product names for a given user name: " + userName + ", products: " + jsonString);
		return jsonString;
	}

	@RequestMapping(value = "/{productName}", method = RequestMethod.GET)
	public String preview(@PathVariable String productName, @RequestParam String themeUUID, @RequestParam String path, HttpServletRequest request, Model model) {
		String result = null;
		result = request.getRequestURL() + "?" + request.getQueryString();
		model.addAttribute("echoURL", result);
		return "echoPage";
	}

	/**
	 * Returns the meta data of a Rules for a given screen
	 * 
	 * @param screenName
	 * @return screen meta data as json document
	 */

	@RequestMapping(value = "rules", method = RequestMethod.GET)
	@ResponseBody
	public String getRulesByScreenName(@RequestParam String screenName) {
		Rule response = null;
		if (screenName == null || screenName.isEmpty() || screenName.equals("")) {
			return createErrorJsonDocument(9090, "Invalid screen name.");
		} else {
			response = applicationManagerService.getRulesByScreenName(screenName);
			if (response == null) {
				logger.info("Returning Error JSON data for the screen : " + screenName);
				return createErrorJsonDocument(9091, "Screen name doesn't exists.");
			} else {
				logger.info("Returning Rule JSON data for the screen : " + screenName);
				try {
					String json = convertToJsonDocument(response);
					return json;
				} catch (Exception e) {
					return createErrorJsonDocument(1234, "Technical Error.");
				}
			}
		}

	}

	/**
	 * returns the list of themes.
	 * 
	 */
	@RequestMapping(value = "themes", method = RequestMethod.GET)
	@ResponseBody
	public String getListOfThemes() {

		String ver = "";
		String name = "";
		logger.info("Getting all themes from servicefacade ");

		List<Theme> themesList = applicationManagerService.getListOfThemes();
		logger.info("Returning List of Themes ");

		try {

			if (themesList == null) {
				logger.info("Returning Error JSON data for the themes list ");
				System.out.println("In the null loop ");
				// error = getErrorObject(123, "Themes doesn't exist.");
				return createErrorJsonDocument(123, "Themes doesn't exist.");

			} else {

				for (Iterator<Theme> itr = themesList.iterator(); itr.hasNext();) {
					Theme themeObj = itr.next();
					themeObj.getId();
					name = themeObj.getName();
					themeObj.getThemeInfo();
					ver = themeObj.getVersion();
					logger.info("name : " + name);
					logger.info("ver :" + ver);
					logger.info("Id : " + themeObj.getId());
					logger.info("Theme Info :" + themeObj.getThemeInfo());
				}
			}
		} catch (Exception e) {
			String errMesg = "Error in fetching list of themes: ";
			System.out.println(e.toString());
			logger.error(errMesg, e);
			return createErrorJsonDocument(1234, "Technical Error.");
		}
		try {
			String json = convertToJsonDocument(themesList);
			return json;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return createErrorJsonDocument(1234, "Technical Error.");
		}

	}

	@RequestMapping(value = "updateScreenConfiguration", method = RequestMethod.POST)
	@ResponseBody
	public String updateScreenConfigurationInfo(@RequestBody String jsonDocument) throws Exception {
		String response = "";
		try {
			logger.info("IN THE UPDATE SCREEN CONFIGURATION INFO METHOD");
			ScreenConfiguration screenConfig = mapper.readValue(jsonDocument, ScreenConfiguration.class);
			String path = screenConfig.getKey();
			logger.info("----------------------------------------------");
			logger.info(this.convertToJsonDocument(screenConfig));

			if (screenConfig.getGraphics() != null) {
				logger.info("Sending the graphics for updating the screenId/List<Graphics> dictionary");
				applicationManagerService.updateGraphicsCollection(screenConfig.getId(), screenConfig.getGraphics());
				logger.info("Returned after updating the screenId/List<Graphics> dictionary");
			}
			if ((screenConfig.getFunctions() != null) || (screenConfig.getRules() != null) || (screenConfig.getText() != null)) {
				logger.info("path = '" + path + "'");
				applicationManagerService.save(screenConfig, path);
			}
			response = convertToJsonDocument(screenConfig);
		} catch (Exception e) {
			logger.error("EXCEPTION THROWN IN UPDATE_SCREEN_CONFIGURATION_INFO", e);
			response = createErrorJsonDocument(1234, "Technical Error.");
		}
		return response;
		// return "Updated Function Objects :" + "  " + jsonString;

	}

	/**
	 * @param screenId
	 * @param graphicsId
	 * @param file
	 * @throws Exception
	 */
	@RequestMapping(value = "/{screenId}/{graphicsId}/addNewImageFormHaldler", method = RequestMethod.POST)
	public void handleFormUpload(@PathVariable long screenId, @PathVariable long graphicsId, @RequestParam("upload") MultipartFile file) throws Exception {

		logger.info("Received a multipart file from AppManager");
		logger.info("For screenId: " + screenId);
		logger.info("For graphicsId: " + graphicsId);
		if (!file.isEmpty()) {

			logger.info("Received a multipart file from AppManager " + file.getOriginalFilename());
			applicationManagerService.addImageToCollection(screenId, graphicsId, file);
			logger.info("Added a multipart file from AppManager " + file.getOriginalFilename());
		} else {
			// return "uploadFailure";
		}
	}

	/**
	 * Creates a error Json document.
	 * 
	 * @param errorCode
	 * @param errorMessage
	 * @return Error as Json Document
	 */
	private String createErrorJsonDocument(long errorCode, String errorMessage) {
		StringBuilder error = new StringBuilder();
		error.append("{\"errorCode\":");
		error.append(errorCode);
		error.append(",\"errorMessage\":\"");
		error.append(errorMessage);
		error.append("\"}");
		return error.toString();
	}

	/**
	 * Converts the given object to Json document
	 * 
	 * @param value
	 * @return
	 * @throws Exception
	 */
	private String convertToJsonDocument(Object value) throws Exception {
		return mapper.writeValueAsString(value);
	}

}
